package de.fme.publishing;

import java.util.Set;

import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.publishing.ChannelImpl;
import org.alfresco.repo.publishing.PublishingEventHelper;
import org.alfresco.repo.publishing.PublishingEventProcessor;
import org.alfresco.repo.publishing.PublishingModel;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.publishing.PublishingEvent;
import org.alfresco.service.cmr.publishing.Status;
import org.alfresco.service.cmr.publishing.StatusUpdate;
import org.alfresco.service.cmr.publishing.channels.Channel;
import org.alfresco.service.cmr.publishing.channels.ChannelService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.urlshortening.UrlShortener;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ParameterCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * @author PloetzJ
 * @since 4.0b
 * 
 * adding tracking asset aspect and short Url property
 */
public class FmePublishingEventProcessor extends PublishingEventProcessor
{
    private static final Log log = LogFactory.getLog(FmePublishingEventProcessor.class);
    
    private ChannelService channelService;
    private NodeService nodeService;
    private UrlShortener urlShortener;
	private PublishingEventHelper eventHelper;
	private TransactionService transactionService;
	private BehaviourFilter behaviourFilter;
	private PublishingInfoHelper publishingInfoHelper;

	public FmePublishingEventProcessor() {
		log.info("fme PublishingEventProcessor loaded.");
	}
    
    public void processEventNode(NodeRef eventNode)
    {
        ParameterCheck.mandatory("eventNode", eventNode);
        try
        {
            updateEventStatus(eventNode, Status.IN_PROGRESS);
            final PublishingEvent event = eventHelper.getPublishingEvent(eventNode);
            String channelName = event.getChannelId();
            final ChannelImpl channel = (ChannelImpl) channelService.getChannelById(channelName);
            if (channel == null)
            {
                fail(eventNode, "No channel found");
            }
            else
            {
                transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>()
                {
                    @Override
                    public Void execute() throws Throwable
                    {
                        try
                        {
                            behaviourFilter.disableBehaviour();
                            channel.publishEvent(event);
                            sendStatusUpdate(channel, event);
                        }
                        finally
                        {
                            behaviourFilter.enableBehaviour();
                        }
                        return null;
                    }
                }, false, true);
                updateEventStatus(eventNode, Status.COMPLETED);
            }
        }
        catch (Exception e)
        {
            log.error("Caught exception while processing publishing event " + eventNode, e);
            fail(eventNode, e.getMessage());
        }
     }
    
    public void sendStatusUpdate(Channel publishChannel, PublishingEvent event)
    {
        StatusUpdate update = event.getStatusUpdate();
    	if (update == null)
        {
            return;
        }
        String message = update.getMessage();
        String nodeUrl = getNodeUrl(publishChannel, update);
        // after shortening the URL we store both long and short URL to the pubEvent through the feedbackService
        if (nodeUrl != null) {
        	publishingInfoHelper.addUrlsToPubEvent(event, nodeUrl);
        }
        Set<String> channels = update.getChannelIds();
        for (String channelId : channels)
        {
            Channel channel = channelService.getChannelById(channelId);
            if (channel != null)
            {
                channel.sendStatusUpdate(message, nodeUrl);
            }
        }
    }

    /**
     * @param publishChannel
     * @param update
     * @return
     */
    private String getNodeUrl(Channel publishChannel, StatusUpdate update)
    {
        NodeRef node = update.getNodeToLinkTo();
        String nodeUrl = null;
        if (node!= null)
        {
            nodeUrl = publishChannel.getUrl(node);
            if (nodeUrl != null)
            {
                nodeUrl = " " + urlShortener.shortenUrl(nodeUrl);
            }
            
        }
        return nodeUrl;
    }
    
    private void updateEventStatus(final NodeRef eventNode, final Status status)
    {
       transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>()
       {
           @Override
           public Void execute() throws Throwable
           {
               nodeService.setProperty(eventNode, PublishingModel.PROP_PUBLISHING_EVENT_STATUS, status.name());
               return null;
           }
       }, false, true);
    }
    
    @Override
    public void setNodeService(NodeService nodeService) {
    	super.setNodeService(nodeService);
    	this.nodeService = nodeService;
	}
    
    @Override
    public void setChannelService(ChannelService channelService) {
    	super.setChannelService(channelService);
    	this.channelService = channelService;
    }
    
    @Override
    public void setUrlShortener(UrlShortener urlShortener) {
    	super.setUrlShortener(urlShortener);
    	this.urlShortener = urlShortener;
    }
    
    @Override
    public void setBehaviourFilter(BehaviourFilter behaviourFilter) {
    	// TODO Auto-generated method stub
    	super.setBehaviourFilter(behaviourFilter);
    	this.behaviourFilter = behaviourFilter;
    }
    
    @Override
    public void setPublishingEventHelper(PublishingEventHelper eventHelper) {
    	// TODO Auto-generated method stub
    	super.setPublishingEventHelper(eventHelper);
    	this.eventHelper = eventHelper;
    }
    
    @Override
    public void setTransactionService(TransactionService transactionService) {
    	// TODO Auto-generated method stub
    	super.setTransactionService(transactionService);
    	this.transactionService = transactionService;
    }
    
	public void setPublishingInfoHelper(PublishingInfoHelper publishingInfoHelper) {
		this.publishingInfoHelper = publishingInfoHelper;
	}
     
}